package com.youlu.campus.service.form.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.common.exception.BusinessException;

import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.VO.req.FormTaskConfigQueryVO;
import com.youlu.campus.entity.WechatConfigInfo;
import com.youlu.campus.entity.form.FormTaskConfig;
import com.youlu.campus.entity.form.SingleFormAnswer;
import com.youlu.campus.entity.form.SingleFormQuestion;
import com.youlu.campus.entity.form.UserFormTaskDetailInfo;
import com.youlu.campus.entity.form.UserFormTaskInfo;
import com.youlu.campus.entity.form.domain.UserSubmitSingleForm;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.form.FormTaskConfigService;
import com.youlu.campus.service.form.SingleFormAnswerService;
import com.youlu.campus.service.form.SingleFormQuestionService;
import com.youlu.campus.service.form.UserFormTaskInfoService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

@Slf4j
@Service
public class FormTaskConfigServiceImpl implements FormTaskConfigService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private SingleFormQuestionService singleFormQuestionService;
    @Autowired
    private SingleFormAnswerService singleFormAnswerService;
    @Autowired
    private PlatformConfigService platformConfigService;
    @Lazy
    @Autowired
    private ActivityService activityService;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;
    @Lazy
    @Autowired
    private UserFormTaskInfoService userFormTaskInfoService;
    private String link = "%s%sindex.html?#/pages/form/write?activityId=6641c82f16993b20604412c8&appId=wxbaba4b2c54e8881a&theme=bluesix&authorizeMode=wechat&formId=%s";
    private String link2 = "%s%sindex.html?#/pages/form/write?activityId=%s&appId=%s&theme=bluesix&authorizeMode=wechat&formId=%s";
    @Value("${sys.fileExportPath:/data/file/campus-admin/}")
    private String fileExportPath;

    @Override
    public FormTaskConfig create(FormTaskConfig req) {
        req.setId(null);
        req.setCreatedTime(new Date());
        if (CollectionUtils.isEmpty(req.getQuestions())) {
            log.error(":>>> 题目为空:{}");
            throw new BusinessException("题目为空");
        }
        if ("activity".equals(req.getType())) {
            ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
            if (Objects.nonNull(activityInfo)) {
                req.setAppId(activityInfo.getWechatAppId());
            }
        }
        List<SingleFormQuestion> questionsCopy = new ArrayList<>();
        for (SingleFormQuestion singleFormQuestion : req.getQuestions()) {
            SingleFormQuestion copy = new SingleFormQuestion();
            BeanUtils.copyProperties(singleFormQuestion, copy);
            questionsCopy.add(copy);
        }
        req = mongoTemplate.insert(req);
        for (SingleFormQuestion question : questionsCopy) {
            List<SingleFormAnswer> answers = new ArrayList<>();
            for (SingleFormAnswer singleFormAnswer : question.getAnswers()) {
                SingleFormAnswer copy = new SingleFormAnswer();
                BeanUtils.copyProperties(singleFormAnswer, copy);
                answers.add(copy);
            }
            question.setFormTaskConfigId(req.getId());
            question = singleFormQuestionService.create(question);
            if (CollectionUtils.isEmpty(answers)) {
                log.info(":>>> 表单项:{},{} 答案为空继续创建", question.getId(), question.getTitle());
                continue;
            }
            for (SingleFormAnswer answer : answers) {
                answer.setSingleFormQuestionId(question.getId());
                singleFormAnswerService.create(answer);
            }
        }
        return req;
    }

    @Override
    public boolean update(FormTaskConfig req) {
        Date date = new Date();
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(req.getId()));
        final String formId = req.getId();
        Update update = new Update();
        boolean toUpdate = false;
        if (StringUtils.isNotBlank(req.getStatus())) {
            update.set("status", req.getStatus());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getName())) {
            update.set("name", req.getName());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getImageUrl())) {
            update.set("imageUrl", req.getImageUrl());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getStatus())) {
            update.set("status", req.getStatus());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getAuthorizeType())) {
            update.set("authorizeType", req.getAuthorizeType());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getBannerUrl())) {
            update.set("bannerUrl", req.getBannerUrl());
            toUpdate = true;
        }
        update.set("detail", req.getDetail());
        if (StringUtils.isNotBlank(req.getBackGroundImageUrl())) {
            update.set("backGroundImageUrl", req.getBackGroundImageUrl());
            toUpdate = true;
        }
        update.set("footerDetail", req.getFooterDetail());
        if (StringUtils.isNotBlank(req.getAfterSubmitDetail())) {
            update.set("afterSubmitDetail", req.getAfterSubmitDetail());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getTheme())) {
            update.set("theme", req.getTheme());
            toUpdate = true;
        }
        if (Objects.nonNull(req.getPublished())) {
            update.set("published", req.getPublished());
            toUpdate = true;
        }
        if (Objects.nonNull(req.getShowNo())) {
            update.set("showNo", req.getShowNo());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getType())) {
            update.set("type", req.getType());
            toUpdate = true;
            if ("activity".equals(req.getType())) {
                if (StringUtils.isNotBlank(req.getActivityId())) {
                    update.set("activityId", req.getActivityId());
                    toUpdate = true;
                    ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
                    if (Objects.nonNull(activityInfo)) {
                        update.set("appId", activityInfo.getWechatAppId());
                    }
                }
            }
        }

        if (StringUtils.isNotBlank(req.getAppId())) {
            update.set("appId", req.getAppId());
            toUpdate = true;
        }
        if (toUpdate) {
            update.set("updatedTime", date);
            UpdateResult updateResult = mongoTemplate.updateFirst(query, update, FormTaskConfig.class);
        }
        // 修改的时候表单题目为空
        if (Objects.isNull(req.getQuestions()) || CollectionUtils.isEmpty(req.getQuestions())) {
            List<SingleFormQuestion> qs = singleFormQuestionService.findByFormTaskConfigId(req.getId());
            if (CollectionUtils.isEmpty(qs)) {
                log.error(":>>> 表单的问题为空:{}", req.getId());
            } else {
                for (SingleFormQuestion question : qs) {
                    singleFormAnswerService.deleteBySingleFormQuestionId(question.getId());
                }
            }
        }
        // 修改的时候表单题目不为空
        else {
            for (SingleFormQuestion q : req.getQuestions()) {
                // 新加的题目
                if (StringUtils.isBlank(q.getId())) {
                    log.info(":>>> 新添加的题目:{}", q.getTitle());
                    List<SingleFormAnswer> answerTodo = new ArrayList<>();
                    for (SingleFormAnswer s : q.getAnswers()) {
                        SingleFormAnswer todo = new SingleFormAnswer();
                        BeanUtils.copyProperties(s, todo);
                        answerTodo.add(todo);
                    }
                    q.setFormTaskConfigId(formId);
                    q = singleFormQuestionService.create(q);
                    if (CollectionUtils.isNotEmpty(answerTodo)) {
                        for (SingleFormAnswer answer : answerTodo) {
                            answer.setSingleFormQuestionId(q.getId());
                            singleFormAnswerService.create(answer);
                        }
                    } else {
                        log.info(":>>> 表单项没有配置答案:{}", formId, q.getId());
                    }
                } else {
                    // 老题目
                    log.info(":>>> 表单是老的题目的题目:{},{}", formId, q.getTitle());
                    List<SingleFormAnswer> answerTodo = new ArrayList<>();
                    for (SingleFormAnswer s : q.getAnswers()) {
                        SingleFormAnswer todo = new SingleFormAnswer();
                        BeanUtils.copyProperties(s, todo);
                        answerTodo.add(todo);
                    }
                    if (Objects.isNull(answerTodo) || CollectionUtils.isEmpty(answerTodo)) {
                        singleFormAnswerService.deleteBySingleFormQuestionId(q.getId());
                    } else {
                        for (SingleFormAnswer answer : answerTodo) {
                            if (StringUtils.isBlank(answer.getId())) {
                                answer.setSingleFormQuestionId(q.getId());
                                singleFormAnswerService.create(answer);
                            } else {
                                singleFormAnswerService.update(answer);
                            }
                        }
                    }

                }
                singleFormQuestionService.update(q);
            }
        }
        return true;
    }

    @Override
    public FormTaskConfig findOne(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        FormTaskConfig config = mongoTemplate.findOne(query, FormTaskConfig.class);
        if (Objects.isNull(config)) {
            log.error(":>>> 数据不存在:{}", id);
            return null;
        }
        List<SingleFormQuestion> qs = singleFormQuestionService.findByFormTaskConfigId(config.getId());
        if (CollectionUtils.isEmpty(qs)) {
            config.setQuestions(qs);
            return config;
        }
        log.info(":>>> 表单的项为:{},{},{}", id, qs.size(), JSON.toJSONString(qs));
        for (SingleFormQuestion q : qs) {
            List<SingleFormAnswer> answers = singleFormAnswerService.findBySingleFormQuestionId(q.getId());
            q.setAnswers(answers);
        }
        config.setQuestions(qs);
        log.info(":>>> 表单的基础数据为:{},{}", id, JSON.toJSONString(config));
        return config;
    }

    @Override
    public boolean delete(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("deleted", true);
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, FormTaskConfig.class);
        return result.getModifiedCount() > 0 ? true : false;
    }

    @Override
    public Page<FormTaskConfig> list(FormTaskConfigQueryVO req) {
        log.info(":>>> 开始获取表单列表:{}", JSON.toJSONString(req));
        if (Objects.isNull(req)) {
            log.error(":>>> 获取表单列表参数错误:证书分组为空");
            throw new BusinessException("获取表单列表参数错误");
        }
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getStatus())) {
            query.addCriteria(Criteria.where("status").is(req.getStatus()));
        }
        if (StringUtils.isNotBlank(req.getActivityId())) {
            query.addCriteria(Criteria.where("activityId").is(req.getActivityId()));
        }
        if (StringUtils.isNotBlank(req.getType())) {
            query.addCriteria(Criteria.where("type").is(req.getType()));
        }
        if (StringUtils.isNotBlank(req.getAppId())) {
            query.addCriteria(Criteria.where("appId").is(req.getAppId()));
        }
        if (StringUtils.isNotBlank(req.getName())) {
            if (StringUtils.isNotBlank(req.getName())) {
                Pattern pattern = Pattern.compile("^.*" + req.getName() + ".*$", Pattern.CASE_INSENSITIVE);
                query.addCriteria(Criteria.where("name").regex(pattern));
            }
        }
        if (StringUtils.isNotBlank(req.getCreatorId())) {
            query.addCriteria(Criteria.where("creatorId").is(req.getCreatorId()));
        }
        query.addCriteria(Criteria.where("deleted").ne(true));
        long count = mongoTemplate.count(query, FormTaskConfig.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<FormTaskConfig> infos = mongoTemplate.find(query.with(pageRequest), FormTaskConfig.class);
        String frontDomain = platformConfigService.getBizFrontDomain();
        String formC = platformConfigService.getFormCatalogue();
        String activityC = platformConfigService.getCatalogue();
        for (FormTaskConfig formTaskConfig : infos) {
            if ("activity".equals(formTaskConfig.getType())) {
                String link21 = String.format(link2, frontDomain, activityC,
                        formTaskConfig.getActivityId(), formTaskConfig.getAppId(), formTaskConfig.getId());
                formTaskConfig.setLinkUrl(link21);
            } else {
                String link11 = String.format(link, frontDomain, formC, formTaskConfig.getId());
                formTaskConfig.setLinkUrl(link11);
            }
            if (StringUtils.isNotBlank(formTaskConfig.getActivityId())) {
                ActivityInfo activityInfo = activityService.findOne(formTaskConfig.getActivityId());
                if (Objects.nonNull(activityInfo)) {
                    if (!"activity".equals(formTaskConfig.getType())) {
                        formTaskConfig.setActivityName("默认");
                    } else {
                        formTaskConfig.setActivityName(activityInfo.getName());
                    }
                }
            }
            if (StringUtils.isNotBlank(formTaskConfig.getAppId())) {
                WechatConfigInfo configInfo = wechatConfigInfoService.find(formTaskConfig.getAppId());
                if (Objects.nonNull(configInfo)) {
                    formTaskConfig.setAppName(configInfo.getName());
                }
            }
        }
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    @Override
    public boolean copy(String formId, String userId) {
        log.info(":>>> 开始复制表单:{}", formId);
        FormTaskConfig form = this.findOne(formId);
        if (Objects.isNull(form)) {
            log.error(":>>> 表单不存在，复制失败:{}", form);
            return false;
        }
        Date date = new Date();
        List<SingleFormQuestion> questions = new ArrayList<>();
        HashMap<String, List<SingleFormAnswer>> answerMap = new HashMap<>();
        for (SingleFormQuestion s : form.getQuestions()) {
            SingleFormQuestion copy = new SingleFormQuestion();
            BeanUtils.copyProperties(s, copy);
            questions.add(copy);
            List<SingleFormAnswer> answersCopy = new ArrayList<>();
            for (SingleFormAnswer singleFormAnswer : s.getAnswers()) {
                SingleFormAnswer copyAnswer = new SingleFormAnswer();
                BeanUtils.copyProperties(singleFormAnswer, copyAnswer);
                answersCopy.add(copyAnswer);
            }
            if (CollectionUtils.isNotEmpty(answersCopy)) {
                answerMap.put(s.getId(), answersCopy);
            }

        }
        FormTaskConfig copyConfig = new FormTaskConfig();
        BeanUtils.copyProperties(form, copyConfig);
        copyConfig.setId(null);
        copyConfig.setCreatedTime(date);
        copyConfig.setCreatorId(userId);
        copyConfig = this.create(copyConfig);
        for (SingleFormQuestion s : questions) {
            s.setFormTaskConfigId(copyConfig.getId());
            SingleFormQuestion copyQuestion = new SingleFormQuestion();
            BeanUtils.copyProperties(s, copyQuestion);
            copyQuestion.setId(null);
            copyQuestion.setCreatedTime(date);
            copyQuestion.setFormTaskConfigId(copyConfig.getId());
            copyQuestion = singleFormQuestionService.create(copyQuestion);
            if (answerMap.containsKey(s.getId())) {
                for (SingleFormAnswer answer : answerMap.get(s.getId())) {
                    SingleFormAnswer copy = new SingleFormAnswer();
                    BeanUtils.copyProperties(answer, copy);
                    copy.setSingleFormQuestionId(copyQuestion.getId());
                    copy.setId(null);
                    copy.setCreatedTime(date);
                    singleFormAnswerService.create(copy);
                }
            }

        }
        return true;
    }

    @Override
    public boolean hasPermission(String currentUserId, String formId, String loginName) {
        FormTaskConfig form = this.findOne(formId);
        if (Objects.isNull(form) || StringUtils.isBlank(form.getCreatorId())) {

            return true;
        } else if (loginName.equals("zhouqiao") || loginName.equals("zhuhuaiqi")) {
            return true;
        } else if (currentUserId.equals(form.getCreatorId())) {
            return true;
        }
        return false;
    }

    @Override
    public void download(String id) {
        log.info(":>>> 开始下载表单文件:{}", id);
        FormTaskConfig form = this.findOne(id);
        Query q = new Query();
        q.addCriteria(Criteria.where("formTaskConfigId").is(id).and("status").is("done"));
        List<UserFormTaskInfo> datas = mongoTemplate.find(q, UserFormTaskInfo.class);
        log.info(":>>> 表单用户数据大小:{},{}", id, datas.size());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(new Date());
        File directory = new File(fileExportPath + dateStr);
        String filePath = "";
        // 创建文件夹
        if (!directory.exists()) {
            boolean hasSucceeded = directory.mkdir();
            if (!hasSucceeded) {
                log.error(":>>> 创建文件夹:{} 失败", fileExportPath + dateStr);
                return;
            }
            filePath = fileExportPath + dateStr + "/" + form.getName();
            File directory1 = new File(fileExportPath + dateStr + "/" + form.getName());
            boolean hasSucceeded2 = directory1.mkdir();
            if (!hasSucceeded2) {
                log.error(":>>> 创建文件夹:{} 失败", fileExportPath + dateStr + "/" + form.getName());
                return;
            }
        }
        for (UserFormTaskInfo u : datas) {
            UserFormTaskInfo u1 = userFormTaskInfoService.findOne(u.getId());
            if (Objects.isNull(u1)) {
                continue;
            }
            File directory2 = new File(fileExportPath + dateStr + "/" + form.getName() + "/" + u.getName());
            boolean hasSucceeded3 = directory2.mkdir();
            if (!hasSucceeded3) {
                log.error(":>>> 创建文件夹:{} 失败", fileExportPath + dateStr + "/" + form.getName() + "/" + u.getName());
                return;
            }
            for (UserFormTaskDetailInfo u2 : u1.getItems()) {

                if (u2.getType().equals("file-upload") || u2.getType().equals("image-upload") || u2.getType().equals("video-upload")) {
                    for (UserSubmitSingleForm u3 : u2.getDatas()) {
                        if (StringUtils.isBlank(u3.getStringValue())) {
                            continue;
                        }
                        this.generateFile(u3.getStringValue(), fileExportPath + dateStr + "/" + form.getName() + "/" + u.getName());
                    }
                }
            }
        }
        log.info(":>>> 结束生成表单文件:{}", id);
        // 开始压缩成ZIP格式


    }

    /**
     * @param fileUrl:远程文件的URL
     * @param savePath:本地保存路径
     */
    private void generateFile(String fileUrl, String savePath) {
        try {
            URL url = new URL(fileUrl);
            URLConnection connection = url.openConnection();
            InputStream inputStream = connection.getInputStream();
            FileOutputStream outputStream = new FileOutputStream(savePath);
            byte[] buffer = new byte[2048 * 3];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.close();
            inputStream.close();
            log.info(":>>> 远程文件生成完成:{}", fileUrl);
        } catch (IOException e) {
            log.error(":>>> 远程文件生成错误，错误信息:{}", e);
        }
    }

    @Override
    public boolean transferCreator(FormTaskConfig req) {
        log.info("transferCreator 开始转移创建者req:{}", JSONObject.toJSONString(req));
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(req.getId()));
        Update update = new Update();
        update.set("creatorId", req.getCreatorId());
        update.set("updatedTime", new Date());
        boolean b = mongoTemplate.updateFirst(query, update, FormTaskConfig.class).getModifiedCount() > 0 ? true : false;
        log.info("transferCreator result:{}", b);
        return b;
    }

}
